package com.example.teesystem.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.teesystem.common.cache.IssueCache;
import com.example.teesystem.common.cache.UserCache;
import com.example.teesystem.common.exception.CustomException;
import com.example.teesystem.common.utils.ExcelUtil;
import com.example.teesystem.common.utils.FileUtil;
import com.example.teesystem.common.utils.Response;
import com.example.teesystem.common.utils.ResultCode;
import com.example.teesystem.entity.*;
import com.example.teesystem.entity.vo.IssueRecord.IssueRecordInsertVo;
import com.example.teesystem.entity.vo.PageResponseVo;
import com.example.teesystem.entity.vo.advancedTrain.Answer;
import com.example.teesystem.entity.vo.issue.*;
import com.example.teesystem.entityDto.*;
import com.example.teesystem.filter.MyHandlerInterceptor;
import com.example.teesystem.mapper.*;
import com.example.teesystem.service.IssueRecordService;
import com.example.teesystem.service.IssueService;
import lombok.AllArgsConstructor;
import org.springframework.beans.BeanUtils;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @author NieYaShi
 * @description 针对表【t_issue】的数据库操作Service实现
 * @createDate 2022-03-28 09:23:20
 */
@Service
@AllArgsConstructor
public class IssueServiceImpl extends ServiceImpl<IssueMapper, Issue>
        implements IssueService {

    private final IssueMapper issueMapper;
    private final CourseMapper courseMapper;
    private final ExamIssueMapper examIssueMapper;
    private final ChapterMapper chapterMapper;
    private final WrongSetMapper wrongSetMapper;
    private final IssueRecordMapper issueRecordMapper;
    private final IssueRecordService issueRecordService;
    private final FeatureTrainingMapper featureTrainingMapper;

    private static final int ERROR = -1;

    public static final String [] issueType = new String[]{"记忆型","理解型","应用型","逻辑型","概念型","综合型"};

    @Override
    public Response addSingleIssue(IssueInsertVo issueInsertVo) {
        Course course = courseMapper.selectById(issueInsertVo.getCourseId());
        if (course == null){
            return Response.error(ResultCode.COURSE_NOT_EXIST_ERROR);
        }
        Chapter chapter = chapterMapper.getChapterByIdAndCourseId(issueInsertVo.getChapterId(), issueInsertVo.getCourseId());
        if (chapter == null){
            return Response.error(ResultCode.CHAPTER_NOT_IN_COURSE_ERROR);
        }

        Issue issue = new Issue();
        BeanUtils.copyProperties(issueInsertVo, issue);
        issue.setUploadUid(MyHandlerInterceptor.getUid());

        int id = ERROR;
        issueMapper.insert(issue);
        id = issue.getId();

        if (id == ERROR) {
            return Response.error(ResultCode.INSERT_ERROR);
        } else {
            IssueCache.issueMap.put(id, issue.getCourseId());
            if(issueInsertVo.isFeature()){
                FeatureTraining featureTraining = new FeatureTraining();
                featureTraining.setIssueId(id);
                featureTraining.setCourseId(issueInsertVo.getCourseId());
                featureTrainingMapper.insert(featureTraining);
            }
            return Response.ok();
        }
    }


    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Response bringInIssue(String ids, Integer courseId,int type) {
        String[] idsStr = ids.split("\\$");
        List<Integer> idArray = new ArrayList<>();
        for (String idStr : idsStr) {
            idArray.add(Integer.parseInt(idStr));
        }
        List<Issue> issues = issueMapper.getIssuesByIds(idArray);
        for (Issue issue : issues) {
            String url = "";
            if (issue.getUrl() != null && !issue.getUrl().equals("")) {
                try {
                    url = FileUtil.CopyFile(issue.getUrl(), courseId);
                } catch (Exception e) {
                    System.out.println(e.getMessage());
                    e.printStackTrace();
                    return Response.error(ResultCode.FILE_COPY_FAILURE.getMsg(), ResultCode.FILE_COPY_FAILURE.getCode());
                }
            }

            issue.setId(null);
            issue.setKnowledgeList("");
            issue.setUrl(url);
            issue.setReferenceNum(0);
            issue.setCourseId(courseId);
            issue.setUploadUid(MyHandlerInterceptor.getUid());
            issue.setTrainingExam(type);

            int id = ERROR;
            issueMapper.insert(issue);
            id = issue.getId();
            if (id == ERROR) {
                return Response.error(ResultCode.INSERT_ERROR);
            }
            IssueCache.issueMap.put(id, issue.getCourseId());
        }
        return Response.ok();
    }


    @Override
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public Response importIssue(MultipartFile file, int course_id, int chapterId) {
        String fileName = file.getOriginalFilename();//获取文件名
        String pattern = fileName.substring(fileName.lastIndexOf(".") + 1);//获取文件的后缀名
        List<List<String>> listContent;
        int uid = MyHandlerInterceptor.getUid();
        List<Integer> chapterIds = chapterMapper.getIdByCourseId(course_id);
        String [] s = new String[]{"记忆型","理解型","应用型","逻辑型","概念型","综合型"};
        if(!chapterIds.contains(chapterId)) {
            return Response.error(ResultCode.PARAMETER_ERROR);
        }
        try {
            if (file != null) {
                //文件类型判断
                if (!ExcelUtil.isEXCEL(file)) {
                    return Response.error(ResultCode.NOT_EXCEL.getMsg(), ResultCode.NOT_EXCEL.getCode());
                } else {
                    listContent = ExcelUtil.readExcelContents(file, pattern, 11);
                    //文件内容判断
                    if (listContent.isEmpty()) {
                        return Response.error(ResultCode.FILE_EMPTY.getMsg(), ResultCode.FILE_EMPTY.getCode());
                    } else {
                        Course course = courseMapper.selectById(course_id);
                        if (course == null) {
                            return Response.error(ResultCode.PARAMETER_MISS.getMsg(), ResultCode.PARAMETER_MISS.getCode());
                        }
                        String path = FileUtil.FILE_PATH + FileUtil.ISSUE;
                        //    循环遍历
                        for (List<String> strings : listContent) {
                            System.out.println(strings);
                            Issue issue = new Issue();
                            //      读取excel表格中的数据
                            issue.setQuestion(strings.get(0));
                            issue.setSelectionA(strings.get(1));
                            issue.setSelectionB(strings.get(2));
                            issue.setSelectionC(strings.get(3));
                            issue.setSelectionD(strings.get(4));
                            issue.setAnswer(strings.get(5));
                            issue.setUrl(path + course.getId() + "/" + strings.get(6));
                            issue.setDifficulty((int) Float.parseFloat(strings.get(7)));
                            issue.setTrainingExam((int) Float.parseFloat(strings.get(8)));
                            issue.setType((int) Float.parseFloat(strings.get(9)));
                            issue.setAnalysis(strings.get(10));
                            issue.setUploadUid(uid);
                            issue.setCourseId(course_id);
                            issue.setChapterId(chapterId);

                            if(strings.get(11)==null || strings.get(11).equals("")){
                                issue.setIssueType(s[(int) (Math.random() * 6)]);
                            }else {
                                issue.setIssueType(strings.get(11));
                            }

                            issueMapper.insert(issue);
                            IssueCache.issueMap.put(issue.getId(), issue.getCourseId());
                        }
                    }
                }
            } else {
                return Response.error(ResultCode.FILE_IMPORT_FAILURE.getMsg(), ResultCode.FILE_IMPORT_FAILURE.getCode());
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return Response.ok();
    }

    @Override
    public Response updateIssue(IssueUpdateVo issueUpdateVo) {
        try {
            if (issueUpdateVo.getChapterId() != null){
                Chapter chapter = chapterMapper.getChapterByIdAndCourseId(issueUpdateVo.getChapterId(), issueUpdateVo.getCourseId());
                if (chapter == null){
                    return Response.error(ResultCode.CHAPTER_NOT_IN_COURSE_ERROR);
                }
            }
            Issue check = issueMapper.getIssueByIdAndCourseId(issueUpdateVo.getId(), issueUpdateVo.getCourseId());
            if (check != null) {
                Issue issue = new Issue();
                BeanUtils.copyProperties(issueUpdateVo, issue);
                issue.setUploadUid(MyHandlerInterceptor.getUid());
                issueMapper.updateById(issue);
                IssueCache.issueMap.put(issue.getId(), issue.getCourseId());
                return Response.ok();
            } else {
                return Response.error(ResultCode.ISSUE_NOT_EXIST_ERROR);
            }
        } catch (Exception e) {
            return Response.error(ResultCode.UPDATE_MESSAGE_ERROR.getMsg(), ResultCode.UPDATE_MESSAGE_ERROR.getCode());
        }
    }

    @Override
    public Response deleteIssue(int id) {
        try {
            List<ExamIssue> examIssueList = examIssueMapper.getExamIssueByIssueId(id);
            if (examIssueList.size() != 0) {
                return Response.error(ResultCode.ISSUE_DELETE_ERROR);
            }
            issueMapper.deleteIssue(id);
            return Response.ok();
        } catch (Exception e) {
            return Response.error(ResultCode.UPDATE_MESSAGE_ERROR.getMsg(), ResultCode.UPDATE_MESSAGE_ERROR.getCode());
        }
    }

    @Override
    public List<IssueExcel> outPutIssue(String ids, Integer courseId) {
        String[] idsStr = ids.split("\\$");
        List<Integer> idArray = new ArrayList<>();
        for (String idStr : idsStr) {
            idArray.add(Integer.parseInt(idStr));
        }
        List<Issue> issues = issueMapper.getIssuesByIds(idArray);
        List<IssueExcel> issueExcelList = new ArrayList<>();
        for (Issue issue : issues) {
            issueExcelList.add(new IssueExcel(issue));
        }
        System.out.println(issueExcelList);
        return issueExcelList;
    }

    @Override
    public Response getIssueByMultiCondition(IssueSelectVo issueSelectVo) {
        Page<Issue> page = new Page<>(issueSelectVo.getCur(), issueSelectVo.getSize());
        QueryWrapper<Issue> wrapper = new QueryWrapper<>();
        wrapper.eq(issueSelectVo.getCourseId() != null, "course_id", issueSelectVo.getCourseId())
                .eq(issueSelectVo.getTrainingExam() != null, "training_exam", issueSelectVo.getTrainingExam())
                .eq(issueSelectVo.getDifficulty() != null, "difficulty", issueSelectVo.getDifficulty())
                .eq(issueSelectVo.getType() != null, "type", issueSelectVo.getType())
                .eq(issueSelectVo.getChapterId() != null, "chapter_id", issueSelectVo.getChapterId())
                .like(issueSelectVo.getKeyWords() != null, "question", issueSelectVo.getKeyWords());
        Page<Issue> myPage = this.page(page, wrapper);
        List<Issue> issueList = myPage.getRecords();
        List<IssueList> issueLists = new ArrayList<>();
        for (Issue issue : issueList) {
            List<IssueRecord> recordList = issueRecordMapper.getRecordByIssueId(issue.getId());
            issueLists.add(new IssueList(issue, recordList));
        }
        return Response.ok(new PageResponseVo<>(issueLists, myPage.getCurrent(), myPage.getSize(), myPage.getPages()) );
    }

    @Override
    public Response getIssueByMultiConditionInExamDataBase(IssueSelectVo1 issueSelectVo1) {
        Page<Issue> page = new Page<>(issueSelectVo1.getCur(), issueSelectVo1.getSize());
        QueryWrapper<Issue> wrapper = new QueryWrapper<>();
        wrapper.eq("course_id", issueSelectVo1.getCourseId())
                .eq("training_exam", 1)
                .eq("type", issueSelectVo1.getType())
                .eq(issueSelectVo1.getDifficulty() != null, "difficulty", issueSelectVo1.getDifficulty())
                .eq(issueSelectVo1.getChapterId() != null, "chapter_id", issueSelectVo1.getChapterId())
                .like(issueSelectVo1.getKeyWords() != null, "question", issueSelectVo1.getKeyWords());
        Page<Issue> myPage = this.page(page, wrapper);
        List<Issue> issueList = myPage.getRecords();
        List<IssueList> issueLists = new ArrayList<>();
        for (Issue issue : issueList) {
            List<IssueRecord> recordList = issueRecordMapper.getRecordByIssueId(issue.getId());
            issueLists.add(new IssueList(issue, recordList));
        }
        return Response.ok(new PageResponseVo<>(issueLists, myPage.getCurrent(), myPage.getSize(), myPage.getPages()));
    }

    @Override
    public Response getIssueMsg(Integer id) {
        Issue issue = issueMapper.getIssueMessageById(id);
        if(issue == null){
            return Response.error(ResultCode.GET_ERROR);
        }
        User def = new User();
        def.setMyName("用户未找到");
        IssueMessage issueMessage = new IssueMessage(issue);
        if (issueMessage.getUploadUid() != null) {
            User u1 = UserCache.userMap.getOrDefault(issueMessage.getUploadUid(), def);
            issueMessage.setUploadName(u1.getMyName());
        }
        Chapter chapter = chapterMapper.selectById(issueMessage.getChapterId());
        issueMessage.setChapterMessage(chapter.getMessage());
        return Response.ok(issueMessage);
    }

    @Override
    public Response getTypeVisibility(IssueVisibilityVo issueVisibilityVo) {
        int courseId = issueVisibilityVo.getCourseId();
        int trainingExam = issueVisibilityVo.getTrainingExam();
        QueryWrapper<Issue> issueQueryWrapper = new QueryWrapper<>();
        issueQueryWrapper
                .eq("training_exam", trainingExam)
                .eq("course_id", courseId);
        List<Issue> issueList = issueMapper.selectList(issueQueryWrapper);
        Map<Integer, List<Issue>> recodeMap = issueList.stream().collect(Collectors.groupingBy(
                Issue::getType));

        List<IssueVisibility> result = new ArrayList<>();
        for(Integer key : recodeMap.keySet()){
            result.add(new IssueVisibility(key, recodeMap.get(key).size()));
        }

        return Response.ok(result);
    }

    @Override
    public Response getDifficultyVisibility(IssueVisibilityVo issueVisibilityVo) {
        int courseId = issueVisibilityVo.getCourseId();
        int trainingExam = issueVisibilityVo.getTrainingExam();
        QueryWrapper<Issue> issueQueryWrapper = new QueryWrapper<>();
        issueQueryWrapper
                .eq("training_exam", trainingExam)
                .eq("course_id", courseId);
        List<Issue> issueList = issueMapper.selectList(issueQueryWrapper);
        Map<Integer, List<Issue>> recodeMap = issueList.stream().collect(Collectors.groupingBy(
                Issue::getDifficulty));

        List<IssueVisibility> result = new ArrayList<>();
        for(Integer key : recodeMap.keySet()){
            result.add(new IssueVisibility(key, recodeMap.get(key).size()));
        }

        return Response.ok(result);
    }

    @Override
    public Response getTypeRefNumVisibility(IssueVisibilityVo issueVisibilityVo) {
        int courseId = issueVisibilityVo.getCourseId();
        int trainingExam = issueVisibilityVo.getTrainingExam();
        QueryWrapper<Issue> issueQueryWrapper = new QueryWrapper<>();
        issueQueryWrapper
                .eq("training_exam", trainingExam)
                .eq("course_id", courseId);
        List<Issue> issueList = issueMapper.selectList(issueQueryWrapper);
        Map<Integer, List<Issue>> recodeMap = issueList.stream().collect(Collectors.groupingBy(
                Issue::getType));

        List<IssueVisibility> result = new ArrayList<>();
        for(Integer key : recodeMap.keySet()){
            int sum = 0;
            for (Issue issue : recodeMap.get(key)){
                sum += issue.getReferenceNum();
            }
            if(sum == 0) {
                continue;
            }
            result.add(new IssueVisibility(key, sum));
        }

        return Response.ok(result);
    }

    @Override
    public Response getDifficultyTypeVisibility(IssueVisibilityVo issueVisibilityVo) {
        int courseId = issueVisibilityVo.getCourseId();
        int trainingExam = issueVisibilityVo.getTrainingExam();
        QueryWrapper<Issue> issueQueryWrapper = new QueryWrapper<>();
        issueQueryWrapper
                .eq("training_exam", trainingExam)
                .eq("course_id", courseId);
        List<Issue> issueList = issueMapper.selectList(issueQueryWrapper);
        Map<Integer, List<Issue>> recodeMap = issueList.stream().collect(Collectors.groupingBy(
                Issue::getDifficulty));

        List<List<FormatVisibility>> lists = new ArrayList<>();
        for(Integer diff : recodeMap.keySet()){
            Map<Integer, List<Issue>> map = recodeMap.get(diff).stream().collect(Collectors.groupingBy(Issue::getType));
            List<FormatVisibility> l = new ArrayList<>();
            for (Integer key : map.keySet()){
                l.add(new FormatVisibility(diff, key, map.get(key).size()));
            }
            lists.add(l);
        }

        return Response.ok(lists);
    }

    @Override
    public Response getInterestIssue(int courseId, int difficulty, int type, int chapterId) {
        if(chapterId!=-1){
            Chapter chapter = chapterMapper.selectById(chapterId);
            if(chapter!=null){
                if(chapter.getCourseId()!=courseId) {
                    return Response.error(ResultCode.PARAMETER_ERROR);
                }
            }
        }
        List<Issue> issueList = issueMapper.getInterestIssue(courseId,difficulty,type,chapterId);
        List<IssueSimpleMessage> issueSimpleMessages = new ArrayList<>();
        if(issueList!=null || issueList.size()!=0){
            for (Issue issue : issueList) {
                issueSimpleMessages.add(new IssueSimpleMessage(issue));
            }
        }
        return Response.ok(issueSimpleMessages);
    }

    @Override
    public Response checkAnswer(int issueId, String answer) {
        Issue issue = issueMapper.selectById(issueId);
        if (issue == null) {
            return Response.error(ResultCode.ISSUE_NOT_EXIST_ERROR);
        }

        issueRecordService.addIssueRecordService(new IssueRecordInsertVo(issueId, answer));

        if (checkAnswer(issue.getAnswer(), answer)){
            return Response.ok(new AnswerMessage(issue, true));
        }else {

            WrongSet def = wrongSetMapper.getWrongSetByStuIdAndIssueId(MyHandlerInterceptor.getUid(), issueId);
            if (def == null){
                WrongSet wrongSet = new WrongSet();
                wrongSet.setIssueId(issueId);
                wrongSet.setStudentId(MyHandlerInterceptor.getUid());
                wrongSet.setCourseId(issue.getCourseId());
                int ERROR = -1;
                int id = ERROR;
                wrongSetMapper.insert(wrongSet);
                id = wrongSet.getId();
                if (id == ERROR){
                    throw new CustomException(ResultCode.INSERT_ERROR);
                }
            }
            return Response.ok(new AnswerMessage(issue, false));
        }

    }

    @Override
    public IssueSimpleAnswer checkAnswer(Answer answer) {
        Issue issue = issueMapper.getIssueMessageById(answer.getIssueId());

        issueRecordService.addIssueRecordService(new IssueRecordInsertVo(answer.getIssueId(), answer.getAnswer()));

        if (checkAnswer(issue.getAnswer(), answer.getAnswer())){
            return new IssueSimpleAnswer(new IssueSimpleMessage(issue), true);
        }else {

            WrongSet def = wrongSetMapper.getWrongSetByStuIdAndIssueId(MyHandlerInterceptor.getUid(), answer.getIssueId());
            if (def == null){
                WrongSet wrongSet = new WrongSet();
                wrongSet.setIssueId(answer.getIssueId());
                wrongSet.setStudentId(MyHandlerInterceptor.getUid());
                wrongSet.setCourseId(issue.getCourseId());
                int ERROR = -1;
                int id = ERROR;
                wrongSetMapper.insert(wrongSet);
                id = wrongSet.getId();
                if (id == ERROR){
                    throw new CustomException(ResultCode.INSERT_ERROR);
                }
            }

            return new IssueSimpleAnswer(new IssueSimpleMessage(issue), false);
        }
    }

    @Override
    public Response getSecondGameIssue(int courseId, int type) {
        List<Issue> issues = issueMapper.getSecondGameIssue(courseId,type);
        List<IssueMessage> issueMessages = new ArrayList<>();

        for(Issue issue:issues){
            issueMessages.add(new IssueMessage(issue));
        }
        return Response.ok(issueMessages);
    }

    private Boolean checkAnswer(String realAnswer, String studentAnswer){
        String[] realAnswers = realAnswer.toUpperCase().split("\\$");
        String[] studentAnswers = studentAnswer.toUpperCase().split("\\$");

        if (realAnswers.length != studentAnswers.length){
            return false;
        }else {
            List<String> rightAnswer = Arrays.asList(realAnswers);
            boolean judge = true;
            for (String s:studentAnswers){
                if(!rightAnswer.contains(s)){
                    judge = false;
                    break;
                }
            }
            return judge;
        }
    }

}




